package com.jcbase.controller;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcbase.core.BaseConstance;
import com.jcbase.core.auth.interceptor.AuthorityInterceptor;
import com.jcbase.core.auth.interceptor.SysLogInterceptor;
import com.jcbase.core.util.CommonUtils;
import com.jcbase.core.vo.AjaxResult;
import com.jcbase.core.weixin.interceptor.JSApiInterceptor;
import com.jcbase.core.weixin.interceptor.Oauth2Interceptor;
import com.jcbase.dto.PayAttach;
import com.jcbase.model.RisebdAppointTaking;
import com.jcbase.model.RisebdCouponMember;
import com.jcbase.model.RisebdMember;
import com.jcbase.model.RisebdMemberAppoint;
import com.jcbase.model.RisebdPayOrder;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.core.Controller;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.weixin.sdk.api.PaymentApi;
import com.jfinal.weixin.sdk.api.PaymentApi.TradeType;
import com.jfinal.weixin.sdk.kit.IpKit;
import com.jfinal.weixin.sdk.kit.PaymentKit;
import com.jfinal.weixin.sdk.utils.JsonUtils;

/**
 * 支付
 * 
 * @author yiz
 * @date 2016年10月25日 下午1:46:50
 * @version 1.0.0 
 */
@Clear({ AuthorityInterceptor.class, SysLogInterceptor.class })
@Before({ Oauth2Interceptor.class, JSApiInterceptor.class })
public class PayController extends Controller {

	private static final Logger logger = LoggerFactory.getLogger(PayController.class);
	private AjaxResult ajax = new AjaxResult();
	//商户相关资料
	String appid = PropKit.get("appId");
	String partner = PropKit.get("mch_id");
	String paternerKey = PropKit.get("paternerKey");
	String notify_url = PropKit.get("we_notify_url");

	/**
	 *  预约去支付跳转
	 */
	public void appointmentToPay() {
		String memberid = getCookie(BaseConstance.MEMBERID_COOKIE_KEY);
		String appointId = getPara(0);
		RisebdMemberAppoint memberAppoint = RisebdMemberAppoint.me.getById(appointId);
		if (null != memberAppoint) {
			RisebdAppointTaking appointTaking = RisebdAppointTaking.me.getByAppointId(appointId);
			memberAppoint.setRisebdAppointTaking(appointTaking);
		}
		List<RisebdCouponMember> couponMembers = RisebdCouponMember.me.getByMemberId(memberid);
		RisebdMember risebdMember = RisebdMember.me.getById(memberid);
		setAttr("memberAppoint", memberAppoint);
		setAttr("risebdMember", risebdMember);
		setAttr("couponMembers", couponMembers);
		render("appointmentToPay.jsp");
	}

	public void appointmentYePay() {
		String openId = getCookie(BaseConstance.OPENID_COOKIE_KEY);
		String appointId = getPara("appointId");
		String couponId = getPara("couponId");
		RisebdMember risebdMember = RisebdMember.me.getMemberByOpenid(openId);
		String memberId = null;
		if (null == risebdMember) {
			ajax.addError("用户未注册！");
			renderJson(ajax);
			return;
		}
		if (risebdMember.getAccount() != null && risebdMember.getAccount().doubleValue() <= 0) {
			ajax.addError("用户余额不足！");
			renderJson(ajax);
			return;
		}
		if (CommonUtils.isNotEmpty(couponId)) {//当使用优惠券时
			//查询用户优惠券
			RisebdCouponMember coupon = RisebdCouponMember.me.getById(couponId);
			if (coupon == null) {
				ajax.addError("优惠券不存在");
				renderJson(ajax);
				return;
			} else if (coupon.getCouponStatus() != 1) {
				ajax.addError("优惠券无效");
				renderJson(ajax);
				return;
			}
		}
		RisebdMemberAppoint memberAppoint = RisebdMemberAppoint.me.getById(appointId);
		if (null == memberAppoint || memberAppoint.getStatus() != 0 || memberAppoint.getPayType() != 0) {
			ajax.addError("订单已经不存在或已支付");
			renderJson(ajax);
			return;
		}
		if (memberAppoint.getNowPrice() == null || memberAppoint.getNowPrice().doubleValue() <= 0) {
			ajax.addError("订单金额不合法，请确认后再操作!");
			renderJson(ajax);
			return;
		}
		if (risebdMember.getAccount().doubleValue() - memberAppoint.getNowPrice().doubleValue() < 0) {
			ajax.addError("用户余额不足！");
			renderJson(ajax);
			return;
		}
		//减少余额
		try {
			boolean payFlag = updatePayAppoint(3, risebdMember, memberAppoint);
			if (!payFlag) {
				ajax.addError("支付失败，请重试！");
				renderJson(ajax);
				return;
			}
			renderJson(ajax.success("使用余额支付成功！"));
			return;
		} catch (Exception e) {
			ajax.addError("支付失败，出现异常！");
			renderJson(ajax);
			return;
		}
	}

	/**
	 * @category 更新支付后预约信息
	 * @param payType 1，微信支付，2 余额支付，3，支付宝支付
	 * @param risebdMember
	 * @param risebdMemberAppoint 
	 * @return
	 * @throws Exception
	 */
	@Before(Tx.class)
	public boolean updatePayAppoint(int payType, RisebdMember risebdMember, RisebdMemberAppoint risebdMemberAppoint)
			throws Exception {
		boolean flag = false;
		if (payType == 1) {//微信支付
			flag = risebdMemberAppoint.set("pay_type", 1).update();
		} else if (payType == 2) {//余额支付
			flag = risebdMemberAppoint.set("pay_type", 2).update();
			flag = risebdMember.set("account", risebdMember.getAccount().subtract(risebdMemberAppoint.getNowPrice()))
					.update();
		} else if (payType == 3) {//支付宝支付
			flag = risebdMemberAppoint.set("pay_type", 3).update();
		}
		return flag;
	}

	/**
	 * @category 支付
	 */
	public void appointmentWePay() {
		String openId = getCookie(BaseConstance.OPENID_COOKIE_KEY);
		String appointId = getPara("appointId");
		String couponId = getPara("couponId");
		if (CommonUtils.isEmpty(appid) || CommonUtils.isEmpty(partner) || CommonUtils.isEmpty(paternerKey)
				|| CommonUtils.isEmpty(notify_url)) {
			ajax.addError("支付参数不正确！");
			renderJson(ajax);
			return;
		}
		RisebdMember risebdMember = RisebdMember.me.getMemberByOpenid(openId);
		String memberId = null;
		if (null != risebdMember && CommonUtils.isNotEmpty(risebdMember.getMobile())) {
			ajax.addError("用户未注册！");
			renderJson(ajax);
			return;
		}
		memberId = risebdMember.getId();
		if (CommonUtils.isNotEmpty(couponId)) {//当使用优惠券时
			//查询用户优惠券
			RisebdCouponMember coupon = RisebdCouponMember.me.getById(couponId);
			if (coupon == null) {
				ajax.addError("优惠券不存在");
				renderJson(ajax);
				return;
			} else if (coupon.getCouponStatus() != 1) {
				ajax.addError("优惠券无效");
				renderJson(ajax);
				return;
			}
		}
		RisebdMemberAppoint memberAppoint = RisebdMemberAppoint.me.getById(appointId);
		if (null == memberAppoint || memberAppoint.getStatus() != 0 || memberAppoint.getPayType() != 0) {
			ajax.addError("订单已经不存在或已支付");
			renderJson(ajax);
			return;
		}
		if (memberAppoint.getNowPrice() == null || memberAppoint.getNowPrice().doubleValue() <= 0) {
			ajax.addError("订单金额不合法，请确认后再操作!");
			renderJson(ajax);
			return;
		}
		Map<String, String> params = new HashMap<String, String>();
		params.put("appid", appid);
		params.put("mch_id", partner);
		params.put("body", "订单支付-微信在线支付");
		String out_trade_no = System.currentTimeMillis() + "";
		params.put("out_trade_no", out_trade_no);
		int price = ((int) (memberAppoint.getNowPrice().doubleValue() * 100));
		params.put("total_fee", price + "");
		params.put("attach", JsonKit.toJson(new PayAttach(openId, appointId, price + "")));

		String ip = IpKit.getRealIp(getRequest());
		if (StrKit.isBlank(ip)) {
			ip = "127.0.0.1";
		}

		params.put("spbill_create_ip", ip);
		params.put("trade_type", TradeType.JSAPI.name());
		params.put("nonce_str", System.currentTimeMillis() / 1000 + "");
		params.put("notify_url", notify_url);
		params.put("openid", openId);

		String sign = PaymentKit.createSign(params, paternerKey);
		params.put("sign", sign);

		String xmlResult = PaymentApi.pushOrder(params);
		Map<String, String> result = null;

		try {
			result = PaymentKit.xmlToMap(xmlResult);
		} catch (Exception e) {
			ajax.addError("统一下单异常");
			renderJson(ajax);
			return;
		}

		String return_code = result.get("return_code");
		String return_msg = result.get("return_msg");
		if (StrKit.isBlank(return_code) || !"SUCCESS".equals(return_code)) {
			ajax.addError(return_msg);
			renderJson(ajax);
			return;
		}
		String result_code = result.get("result_code");
		if (StrKit.isBlank(result_code) || !"SUCCESS".equals(result_code)) {
			ajax.addError(return_msg);
			renderJson(ajax);
			return;
		}
		// 以下字段在return_code 和result_code都为SUCCESS的时候有返回
		String prepay_id = result.get("prepay_id");

		Map<String, String> packageParams = new HashMap<String, String>();
		packageParams.put("appId", appid);
		packageParams.put("timeStamp", System.currentTimeMillis() / 1000 + "");
		packageParams.put("nonceStr", System.currentTimeMillis() + "");
		packageParams.put("package", "prepay_id=" + prepay_id);
		packageParams.put("signType", "MD5");
		String packageSign = PaymentKit.createSign(packageParams, paternerKey);
		packageParams.put("paySign", packageSign);

		String jsonStr = JsonUtils.toJson(packageParams);
		ajax.success(jsonStr);
		renderJson(ajax);
	}

	public void wePayNotify() {
		//获取所有的参数
		StringBuffer sbf = new StringBuffer();

		Enumeration<String> en = getParaNames();
		while (en.hasMoreElements()) {
			Object o = en.nextElement();
			sbf.append(o.toString() + "=" + getPara(o.toString()));
		}

		logger.error("支付通知参数：" + sbf.toString());

		// 支付结果通用通知文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
		String xmlMsg = HttpKit.readData(getRequest());
		System.out.println("支付通知=" + xmlMsg);
		Map<String, String> params = PaymentKit.xmlToMap(xmlMsg);

		String appid = params.get("appid");
		//商户号
		String mch_id = params.get("mch_id");
		String result_code = params.get("result_code");
		String openId = params.get("openid");
		//交易类型
		String trade_type = params.get("trade_type");
		//付款银行
		String bank_type = params.get("bank_type");
		// 总金额
		String total_fee = params.get("total_fee");
		//现金支付金额
		String cash_fee = params.get("cash_fee");
		// 微信支付订单号
		String transaction_id = params.get("transaction_id");
		// 商户订单号
		String out_trade_no = params.get("out_trade_no");
		// 支付完成时间，格式为yyyyMMddHHmmss
		String time_end = params.get("time_end");

		/////////////////////////////以下是附加参数///////////////////////////////////

		String attach = params.get("attach");
		String fee_type = params.get("fee_type");
		String is_subscribe = params.get("is_subscribe");
		String err_code = params.get("err_code");
		String err_code_des = params.get("err_code_des");

		// 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
		// 避免已经成功、关闭、退款的订单被再次更新
		RisebdPayOrder order = RisebdPayOrder.me.getOrderByTransactionId(transaction_id);
		if (order == null) {
			if (PaymentKit.verifyNotify(params, paternerKey)) {
				if (("SUCCESS").equals(result_code)) {
					//更新订单信息
					logger.warn("更新订单信息:" + attach);
					PayAttach payAttach = JsonKit.parse(attach, PayAttach.class);
					String appointId = payAttach.getAppointId();
					RisebdMember risebdMember = RisebdMember.me.getMemberByOpenid(openId);
					RisebdMemberAppoint risebdMemberAppoint = RisebdMemberAppoint.me.getById(appointId);
					try {
						//更新预约表
						updatePayAppoint(1, risebdMember, risebdMemberAppoint);
						//更新支付订单
						RisebdPayOrder.me.saveRisebdPayOrder(null, transaction_id, out_trade_no, trade_type, fee_type,
								bank_type, mch_id, appid, openId, risebdMember.getId(), total_fee, cash_fee, null);
						//发送通知等,通知店员
						//CompleteService.sendTemplate(openid, templateId, topColor, jumpUrl, dataItem); TODO
					} catch (Exception e) {
						logger.error("更新预约失败appointId={},openId={},e={}", appointId, openId, e);
					}
					Map<String, String> xml = new HashMap<String, String>();
					xml.put("return_code", "SUCCESS");
					xml.put("return_msg", "OK");
					renderText(PaymentKit.toXml(xml));
					return;
				}
			}
		}
		renderText("");
	}
}
